<template>
  <el-drawer
    :title="titleTips"
    :visible.sync="open"
    :before-close="handleClose"
    ref="drawer"
    size="50%"
  >
    <div class="tenant-drawer-content">
      <el-tabs
        tab-position="left"
        v-model="activeName"
        @tab-click="onClickTab"
        style="height: 100%;"
        class="tenant-drawer-tab"
      >
        <el-tab-pane label="租户信息" name="first">
          <div class="tab-tenant">
            <el-form
              :model="tenantForm"
              :rules="tenantFormRules"
              ref="tenantForm"
              class="tenant-form"
              :label-width="formLabelWidth"
            >
              <el-form-item label="租户名称" prop="userName">
                <el-input
                  v-model="tenantForm.userName"
                  :disabled="tenantNameDisabled"
                  autocomplete="off"
                  placeholder="请输入租户名称"
                ></el-input>
              </el-form-item>
              <el-form-item label="租户描述" prop="description">
                <el-input
                  v-model="tenantForm.description"
                  type="textarea"
                  :autosize="{ minRows: 1, maxRows: 3}"
                  placeholder="请输入描述信息"
                ></el-input>
              </el-form-item>
              <el-form-item label="租户密码" prop="tenantPwd" v-if="isCreate">
                <el-input
                  v-model="tenantForm.tenantPwd"
                  placeholder="请输入密码"
                  autocomplete="off"
                  show-password
                ></el-input>
              </el-form-item>
              <el-form-item label="确认租户密码" prop="tenantVerifyPwd" v-if="isCreate">
                <el-input
                  v-model="tenantForm.tenantVerifyPwd"
                  placeholder="请再次输入密码"
                  autocomplete="off"
                  show-password
                ></el-input>
              </el-form-item>
            </el-form>
            <div class="tenant-drawer-footer">
              <el-button @click="onCloseDrawer">取 消</el-button>
              <el-button
                type="primary"
                @click="onClickNextStep"
                :loading="isCheckingTenantName || tenantLoading"
              >{{ tenantBtnTxt }}</el-button>
            </div>
          </div>
        </el-tab-pane>
        <el-tab-pane label="资源配置" name="second" :disabled="serverDisabled" class="tenant-tab-second">
          <div class="tab-tenant" v-loading="showLoading">
            <el-form
              ref="serviceForm" 
              class="tenant-form"
              :model="serviceForm" 
              :rules="serviceFormRules"
              :label-width="formLabelWidth"
            >
              <el-form-item label="开启服务">
                <el-checkbox
                  :indeterminate="isIndeterminate"
                  :disabled="checkAllDisabled"
                  v-model="checkAll"
                  @change="handleCheckAllChange"
                >全选</el-checkbox>
                <el-checkbox-group
                  v-model="serviceForm.checkedServices"
                  @change="handleCheckedServiceChange"
                >
                  <el-checkbox
                    v-for="service in services"
                    :label="service"
                    :key="service"
                    :disabled="serviceSubmited(service)"
                  >{{service}}</el-checkbox>
                </el-checkbox-group>
              </el-form-item>
              <div v-if="isSelected('hdfs')" class="service-item-box">
                <el-divider content-position="left">HDFS</el-divider>
                <el-form-item label="目录">
                  <span>{{serviceForm.hdfs.url}}</span>
                </el-form-item>
                <el-form-item label="容量配额" prop="hdfs.capacity">
                  <el-tooltip :content="hdfsCapacityTooltip" placement="top">
                    <el-input v-model.number="serviceForm.hdfs.capacity" placeholder="请输入配额（建议分配128的整数倍）">
                      <el-select
                        v-model="serviceForm.hdfs.unit"
                        slot="append"
                        placeholder="请选择"
                        style="width:80px"
                        @change="onChangeUnit"
                      >
                        <el-option label="MB" value="1"></el-option>
                        <el-option label="GB" value="2"></el-option>
                        <el-option label="TB" value="3"></el-option>
                      </el-select>
                    </el-input>
                  </el-tooltip>
                </el-form-item>
                <el-form-item label="文件配额" prop="hdfs.fileNum">
                  <el-input v-model.number="serviceForm.hdfs.fileNum" placeholder="请输入文件数">
                    <template slot="append">个</template>
                  </el-input>
                </el-form-item>
              </div>
              <div v-if="isSelected('hive')" class="service-item-box">
                <el-divider content-position="left">Hive</el-divider>
                <el-form-item label="数据库名">
                  <span>{{serviceForm.hive.databaseName}}</span>
                </el-form-item>
              </div>
              <div v-if="isSelected('hbase')" class="service-item-box">
                <el-divider content-position="left">HBase</el-divider>
                <el-form-item label="命名空间">
                  <span>{{serviceForm.hbase.spaceName}}</span>
                </el-form-item>
              </div>
              <div v-if="yarnMax > 0">
                <div v-if="isSelected('yarn')" class="service-item-box">
                  <el-divider content-position="left">Yarn</el-divider>
                  <el-form-item label="队列名">
                    <span>{{serviceForm.yarn.queueName}}</span>
                  </el-form-item>
                  <el-form-item label="资源占比" prop="yarn.ratio">
                    <el-slider @change="onChangeYarnRatio" v-model="serviceForm.yarn.ratio" :max="yarnMax" show-input input-size="mini" :marks="marks"></el-slider>
                  </el-form-item>
                </div>
              </div>
              <div v-else class="txt-box">Yarn暂无资源可分配，无法为该租户创建Yarn队列</div>
            </el-form>
            <div class="tenant-drawer-footer">
              <el-button @click="onClickPreStep">上一步</el-button>
              <el-button
                type="primary"
                @click="onSubmitService"
                :loading="serviceLoading"
              >{{ serviceLoading ? '提交中 ...' : '确 定' }}</el-button>
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </div>
  </el-drawer>
</template>
<script>
import _ from "lodash";
import { mapState } from "vuex";
import { Message } from "element-ui";
import { SERVICE_OPTIONS, CAPACITY_UNIT_MAP } from "@/const";
import { validateUserNameForElementUI, validatePwdForElementUI, validateVerifyPwdForElementUI, 
validateHdfsFileNumForElementUI, validatePositiveInteger, __validateCbForElementUI, resetForm, formatServiceObj, cleanServiceForm } from "@/utils";
import { managerApi } from "@/request";

export default {
  name: "TenantDrawer",
  props: {
    drawerStatus: {
      type: String,
      default: ''
    },
    tenantForm: {
      type: Object,
      default: {}
    },
    reloadCurPage: {
      type: Boolean,
      default: true
    }
  },
  data() {
    const validateName = (rule, value, callback) => {
        validateUserNameForElementUI(value, { auth: '租户', status: this.drawerStatus }, callback, this.setCheckingTenantNameCallback);
    };
    const validateVerifyPwd = (rule, value, callback) => {
        validateVerifyPwdForElementUI(value, this.tenantForm.tenantPwd, callback);
    };
    const validateHdfsCapacity = (rule, value, callback) => {
        const capacity = this.hdfsMax[this.serviceForm.hdfs.unit]; // 当前所选单位 对应的最大配额
        let msg = validatePositiveInteger(value, {required: true, requireMsg: '请输入HDFS容量配额', max: capacity});
        __validateCbForElementUI(msg, callback);
    };
    const validateYarnRatio = (rule, value, callback) => {
        const msg = (typeof value === "number" && value > 0) ? '' : 'Yarn资源占比不能为0';
        __validateCbForElementUI(msg, callback);
    };
    return {
      formLabelWidth: "120px",
      showLoading: false, // 加载数据时的loading
      serviceLoading: false,
      tenantLoading: false,
      isCheckingTenantName: false,
      hdfsMax: [], // hdfs剩余可用空间
      yarnMax: 0, // yarn的default值+已分配值
      ORIGIN_DESC: '', // 记录description初始值：mounted时初始化；修改提交后，更新该值
      isMounted: false, // computed计算 在 mounted之前执行，以此标识 组件加载过了
      notCreated: false, // 是否已创建资源
      hasGotResource: false, // 标记：仅GET请求一次resource信息
      serviceForm: cleanServiceForm(true),
      checkAll: true, // 初始选中所有服务
      isIndeterminate: false, // 全选框的 不确定状态(选中部分)
      // services: SERVICE_OPTIONS, // 资源组件选项
      serviceFormRules: {
          'hdfs.capacity': [{ required: true, validator: validateHdfsCapacity, trigger: "blur" }],
          'hdfs.fileNum': [{ required: true, validator: validateHdfsFileNumForElementUI, trigger: "blur" }],
          'yarn.ratio': [{ required: true, validator: validateYarnRatio, trigger: "input" }]
      },
      tenantFormRules: {
        userName: [{ required: true, validator: validateName, trigger: "blur" }],
        tenantPwd: [{ required: true, validator: validatePwdForElementUI, trigger: "blur" }],
        tenantVerifyPwd: [{ required: true, validator: validateVerifyPwd, trigger: "blur" }],
        description: [{ max: 200, message: "请输入200以内的字符", trigger: "blur" }]
      }
    };
  },
  computed: {
    ...mapState(["installedServices"]),
    open: {
      get() {
        return !!this.drawerStatus;
      },
      set(val) {
        this.$emit("updateDrawer", null);
      }
    },
    activeName: {
      get() {
        if (
          this.drawerStatus === "CREATE" ||
          this.drawerStatus === "UPDATE"
        ) {
          return "first";
        } else if (this.drawerStatus === "RESOURCE") {
          return "second";
        }
      },
      set(val) {
        // activeName 只能在 UPDATE 和 RESOURCE 状态间切换
        if (val == "second") {
          // 切换至 资源配置
          this.$emit("changeStatus", "RESOURCE");
        } else if (val == "first") {
          // 切换至 编辑租户
          this.$emit("changeStatus", "UPDATE");
        }
      }                                
    },
    services() {
      // 显示系统 “已安装”的组件
      const installedServicesString = this.installedServices.toString();
      return SERVICE_OPTIONS.filter(service => new RegExp(service, 'i').test(installedServicesString));
    },
    checkAllDisabled() {
      return this.services.filter( s => !!this.serviceForm[s].id ).length === this.services.length;
    },
    serverDisabled: {
      // tab-资源配置 只能通过 “下一步” 提交并跳转(当 租户信息有修改 时)
      get() {
        if (
          this.drawerStatus === "CREATE" ||
          (this.drawerStatus === "UPDATE" && this.formDataChanged)
        ) {
            return true;
        } else if (this.drawerStatus === "RESOURCE") {
            return false;
        } else {
          return false;
        }
      },
      set(val) {
        // 点击 tab1 时触发，此时 drawerStatus应为'UPDATE'
        this.$emit("changeStatus", "UPDATE");
      }
    },
    tenantNameDisabled() {
        return !!this.tenantForm.userId;
    },
    isCreate() {
        return !this.tenantForm.userId;
    },
    titleTips() {
        return this.tenantForm.userId ? "编辑租户信息" : "创建租户信息";
    },
    formDataChanged() { // 表单数据 被修改
        return this.isMounted && this.ORIGIN_DESC !== this.tenantForm.description;
    },
    hdfsCapacityTooltip() { // HDFS剩余可用空间
        const unit = this.serviceForm.hdfs.unit;
        let capacity = this.hdfsMax[unit]; // 可用空间查询失败，不能显示undefined
        if(capacity === undefined) {
          capacity = '';
        }
        return `HDFS剩余可用空间 ${capacity} ${CAPACITY_UNIT_MAP[unit]}`;
    },
    marks() { // Slider的可选范围下标
        return {
            0: {
              style: {
                left: '0',
                top: '-48px'
              },
              label: this.$createElement('strong', '0%')
            },
            [this.yarnMax]: {
              style: {
                left: '100%',
                top: '-48px'
              },
              label: this.$createElement('strong', this.yarnMax.toString() + '%')
            }
        }
    },
    tenantBtnTxt() {
      // tenantLoading ? '提交中 ...' : '下一步'
      if (this.isCheckingTenantName) {
        return '租户名校验中 ...';
      } else if (this.tenantLoading) {
        return '提交中 ...';
      } else {
        return '下一步'
      }
    }
  },
  mounted() {
      // 加载后，记录 description初始值
      this.ORIGIN_DESC = this.tenantForm.description;
      this.isMounted = true;
      this.requestServices();
  },
  updated() {
    this.requestServices();
  },
  methods: {
    // 创建租户时，直接分配资源：可直接默认 服务全选；
    // 创建租户时，暂未分配资源：再次打开drawer时（1.通过编辑租户，跳转；2.直接进入 分配资源），如何区分‘是否分配过资源’？
    // GET 请求租户资源时，后台返回的 资源对象 全部为null，则为创建资源
    onCreateTenant() {
        // 创建租户
        let tenant = {
            userName: this.tenantForm.userName,
            password: this.tenantForm.tenantPwd,
            description: this.tenantForm.description
        };
        this.tenantLoading = true;
        managerApi
            .addTenant(tenant)
            .then(res => {
                // 租户创建成功，获取 userId 以进行资源配置
                this.tenantLoading = false;
                this.tenantForm.userId = res.data; // 前端记录id
                Message.success("租户创建成功，可进行资源配置");
                this.$emit('update:reloadCurPage', false); // 加载列表首页
                // 标签切换
                this.serverDisabled = false;
                this.activeName = "second";
            })
            .catch(err => {
                this.tenantLoading = false;
            });
    },
    onUpdateTenant() {
        // 编辑租户时，若无改动（description），则不调接口，直接切换标签
        if (!this.formDataChanged) {
            this.serverDisabled = false;
            this.activeName = "second";
            return;
        }
        // 编辑租户
        let tenant = {
            userId: this.tenantForm.userId,
            description: this.tenantForm.description
        };
        this.tenantLoading = true;
        managerApi
            .updateTenant(tenant)
            .then(res => {
                // 更新租户成功，props中的 tenantForm 即为最新值
                this.tenantLoading = false;
                Message.success("租户更新成功");
                this.$emit('update:reloadCurPage', false); // 加载列表首页
                // 更新表单初始值
                this.ORIGIN_DESC = this.tenantForm.description; // 记录此时提交的值
                // 标签切换
                this.serverDisabled = false;
                this.activeName = "second";
            })
            .catch(err => {
                this.tenantLoading = false;
            });
    },
    onClickNextStep() {
      // 下一步：提交租户基本信息，并跳转tab页
      this.$refs["tenantForm"].validate(valid => {
        if (valid) {
          if (this.isCreate) {
            this.onCreateTenant();
          } else {
            this.onUpdateTenant();
          }
        } else {
          return false;
        }
      });
    },
    onClickPreStep() {
      // 上一步：跳转至上一tab页
      this.activeName = "first";
      this.serverDisabled = true;
    },
    onClickTab(evt) {
      // 通过tabs 切换至“租户信息”时，设置“资源配置”tab不可点击
      if (evt.name === "first") {
        this.serverDisabled = true;
      }
    },
    onGetResource() {
        // step1-先同步Yarn资源
        this.showLoading = true;
        managerApi.syncYARN({level: 1, resourceId: 0}).then(res => {
            // step2-获取yarn的default队列的资源占比
            managerApi.queueList({resourceId: 0}).then(res => {
                // 当前租户可编辑配额 yarnMax = default + 当前租户已分配ratio
                let curTenant = this.tenantForm.userName;
                let defaultAndCurTenantQueue = _.get(res, 'pageList', []).filter(item => {
                  return item.queueName === 'default' || item.queueName === curTenant;
                }).reduce((sum, cur) => {
                  return sum + _.get(cur, 'ratio', 0);
                }, 0);
                this.yarnMax = defaultAndCurTenantQueue;
                // step3-拉取租户的资源信息
                managerApi.getResource({tenantId: this.tenantForm.userId}).then(res => {
                    let serviceObj = res.data[0];
                    this.initServiceForm(serviceObj); // 初始化 资源信息
                    this.showLoading = false;
                }).catch(err => {});
            }).catch(err => {});
        }).catch(err => {})
    },
    getResourceStat() {
        managerApi.getHdfsRemain({parentId: 0}).then(res => {
            // 后端返回 length为4的数组，下标 1-3 依次对应HDFS容量单位MB，GB，TB（下标0空余） 
            this.hdfsMax = res.data || [];
        })
    },
    requestServices() {
        // mounted钩子中：通过 “配置资源”按钮打开drawer时，请求数据
        // updated钩子中：切换标签时，若为 'RESOURCE' 且hasGotResource为false， 则拉取租户的资源数据
        if (this.drawerStatus === "RESOURCE" && !this.hasGotResource) {
            this.onGetResource();
            this.getResourceStat();
            this.hasGotResource = true;
        }
    },
    initServiceForm(serviceObj) {
      // 若资源对象全为 null，则认为是 创建资源，否则认为是 编辑资源；
      // 创建后初始化：默认全选；路径名、库名、队列名等 前端仅做展示，不提交数据
      // 编辑时初始化：根据请求数据，初始化租户选中的服务
      console.log("Init_Service_Form", serviceObj);
      // serviceObj 中仅保留 hdfs/hive/hbase/yarn
      serviceObj = _.pick(serviceObj, this.services);
      let notCreated = Object.values(serviceObj).every(v => !v);
      this.notCreated = notCreated;
      if (notCreated) {
        // 为租户创建资源
        let tenantName = this.tenantForm.userName;
        this.serviceForm.hdfs.url = "dataspace/" + tenantName; // hdfs目录
        this.serviceForm.hive.databaseName = tenantName; // hive数据库名
        this.serviceForm.hbase.spaceName = tenantName; // hbase命名空间
        this.serviceForm.yarn.queueName = tenantName; // yarn队列名
      } else {
        // 编辑资源
        let selectedService = _.toPairs(serviceObj)
          .filter(item => !!item[1])
          .map(item => item[0]);
        // 处理复选框
        this.serviceForm.checkedServices = selectedService;
        this.handleCheckedServiceChange(selectedService);
        // 初始化 已配置资源
        selectedService.map(item => {
          this.serviceForm = formatServiceObj(this.serviceForm, item, serviceObj[item], this.tenantForm.userName);
        })
      }
    },
    handleCheckAllChange(val) {
      // 服务：全选 (val: Boolean值)
      // （1）取消全选时，需要保留已提交的服务选项（2）所有服务项均已提交时，全选框 disabled=true
      let submitedOptions = this.services.filter( s => !!this.serviceForm[s].id );
      this.serviceForm.checkedServices = val ? this.services : submitedOptions;
      // 全选/全不选 isIndeterminate=false
      this.isIndeterminate = false;
    }, 
    handleCheckedServiceChange(val) {
      // 复选框组
      let checkedCount = val.length;
      this.checkAll = checkedCount === this.services.length;
      this.isIndeterminate =
        checkedCount > 0 && checkedCount < this.services.length;
      // 处理数据信息
      this.services.map((item, idx) => {
        this.serviceForm = formatServiceObj(this.serviceForm, item, this.serviceForm[item], this.tenantForm.userName);
      })
    },
    serviceSubmited(service) {
      // yarn可分配资源为0，checkbox不可编辑
      if (service === 'yarn' && this.yarnMax <= 0) {
        return true;
      }
      // 提交过的服务，checkbox不可编辑
      return !!this.serviceForm[service].id;
    },
    isSelected(service) {
      // 是否选择了该项服务 && 当前系统中已安装该组件
      // 未选择的服务，隐藏其配置信息
      let selectedArr = this.serviceForm.checkedServices;
      return _.indexOf(selectedArr, service) >= 0 && _.indexOf(this.services, service) >= 0;
    },
    getResourceToSubmit() {
      // 获取要提交的资源配置信息
      // 未勾选的服务不需要提交（租户列表的资源配置，不能删除资源，须在‘资源管理’模块）
      let form = this.serviceForm;
      let resource = {
        uid: this.tenantForm.userId,
        services: [{}]
      };
      this.serviceForm.checkedServices.map(item => {
        switch (item) {
          case "hdfs":
            resource.services[0][item] = {
              id: parseInt(form.hdfs.id),
              url: form.hdfs.url,
              capacity: parseInt(form.hdfs.capacity),
              fileNum: parseInt(form.hdfs.fileNum),
              unit: parseInt(form.hdfs.unit)
            };
            break;
          case "hive":
            resource.services[0][item] = {
              id: parseInt(form.hive.id),
              databaseName: form.hive.databaseName
            };
            break;
          case "hbase":
            resource.services[0][item] = {
              id: parseInt(form.hbase.id),
              spaceName: form.hbase.spaceName
            };
            break;
          case "yarn":
            resource.services[0][item] = {
              id: parseInt(form.yarn.id),
              queueName: form.yarn.queueName,
              ratio: parseFloat(form.yarn.ratio)
            };
            break;
          default:
            break;
        }
      });
      return resource;
    },
    setCheckingTenantNameCallback(flag) {
      this.isCheckingTenantName = flag;
    },
    onChangeUnit() {
        // HDFS的容量配额单位unit改变时，触发capacity的格式校验
        this.$refs["serviceForm"].validateField('hdfs.capacity');
    },
    onChangeYarnRatio() {
      // yarn可配置时，资源占比不能为0
      // el-slider组件不能自动触发表单校验
      this.$refs["serviceForm"].validateField('yarn.ratio');
    },
    onSubmitService() {
      // 提交服务配置信息
      if (!this.tenantForm.userId) {
        Message.error("没有userId，无法提交资源配置，请关闭弹窗");
        return;
      }
      // 未勾选服务，则不提交信息
      if(this.serviceForm.checkedServices.length == 0) {
        this.notCreated = false;
        this.onCloseDrawer();
        return;
      }
      // 数据校验
      this.$refs["serviceForm"].validate(valid => {
        if (valid) {
          this.serviceLoading = true;
          let data = this.getResourceToSubmit();
          if (this.notCreated) {
            // 创建资源
            managerApi
              .addResource(data)
              .then(res => {
                this.serviceLoading = false;
                this.notCreated = false;
                this.$emit('update:reloadCurPage', false); // 加载列表首页
                this.onCloseDrawer(false);
                // Message.success("资源配置成功");
                Message.success(res.msg); // 当某项资源配置失败时，给出提示（此时code 为 1）
              })
              .catch(err => {
                this.serviceLoading = false;
              });
          } else {
            // 修改资源配额、增加资源
            managerApi
              .updateResource(data)
              .then(res => {
                this.serviceLoading = false;
                this.notCreated = false;
                this.$emit('update:reloadCurPage', false); // 加载列表首页
                this.onCloseDrawer(false);
                // Message.success("修改资源配置成功");
                Message.success(res.msg);
              })
              .catch(err => {
                this.serviceLoading = false;
              });
          }
        } else {}
      })
      // 创建、编辑租户时，资源分配失败，租户仍可以创建成功，用户可后续重新分配资源
      // 此时，后端返回 res.code = 1，资源配置的提示信息在 res.msg 
    },
    onCloseDrawer() {
      // 取消创建/编辑租户
      // 取消编辑 / 点击关闭时：
      //（1）更改drawer展示状态open，清除tenantForm表单；
      //（2）清除serviceForm，清除serviceForm表单，hasGotResource置为false；
      //（3）初始化valueChanged为false，值未改变过
      this.open = false;
      this.isMounted = false;
      this.hasGotResource = false;
      resetForm(this.$refs['tenantForm']);
      resetForm(this.$refs['serviceForm']);
      cleanServiceForm(true);
    },
    handleClose(done) {
      this.onCloseDrawer();
      done();
    }
  }
};
</script>
<style lang="scss" scoped>
.tenant-drawer-content {
  padding: 20px;
  height: calc(100vh - 75px);
  overflow: auto;
}
.tab-tenant {
  display: flex;
  flex-direction: column;
  overflow: auto;
  height: 100%;
  margin: 0 10px;
}
/* 表单部分 */
.tab-tenant .tenant-form {
  height: 100%;
  max-height: 800px; // el-form 默认450px
  overflow: auto;
  flex: 1;
  .txt-box {
      margin: 35px 0 25px 50px;
      color: #999;
  }
  
}
.tenant-drawer-content .tenant-tab-second {
  height: 100%;
}
/* 按钮栏 */
.tab-tenant .tenant-drawer-footer {
  display: flex;
  // margin: 0 auto;
  margin-left: 120px;
  text-align: center;
  > button {
    // flex: 1;
    width: 120px;
  }
}
</style>
<style lang="scss">
/* drawer样式 */
.tenant-drawer-tab .el-tabs__content {
  height: 100%;
  overflow: auto !important;
}
</style>